package com.ciaojian.bytedance.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ciaojian.core.bytedance.auth.ByteDanceTokenProvider;
import com.ciaojian.bytedance.authcontroller.ByteDanceV2AuthController;
import com.ciaojian.bytedance.util.Sign;
import com.ciaojian.bytedance.vo.bytedance.*;
import com.ciaojian.core.bytedance.ByteDanceMiniConfig;
import com.ciaojian.core.bytedance.ByteDancePayConfig;
import com.ciaojian.core.bytedance.ByteDanceSignUtil;
import com.ciaojian.core.enums.business.*;
import com.ciaojian.core.enums.sys.StatusCode;
import com.ciaojian.core.mapper.*;
import com.ciaojian.core.model.*;
import com.ciaojian.core.model.Order;
import com.ciaojian.core.model.dy.DyOrder;
import com.ciaojian.core.model.vo.CouponVo;
import com.ciaojian.core.service.BytePayService;
import com.ciaojian.core.service.CouponService;
import com.ciaojian.core.util.JsonUtil;
import com.ciaojian.core.util.LogUtil;
import com.ciaojian.core.util.RedisUtil;
import com.ciaojian.core.util.Result;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Slf4j
@Service
public class ByteDancePayService {
    @Autowired
    private ByteDanceTokenProvider byteDanceTokenProvider;
    @Resource
    private com.ciaojian.core.mapper.UserMapper UserMapper;
    @Autowired
    private BytePayService bytePayService;
    @Resource
    private DyOrderMapper dyOrderMapper;
    @Resource
    private StoreMapper storeMapper;
    @Resource
    private WorkerMapper workerMapper;
    @Resource
    private MyCouponMapper myCouponMapper;
    @Resource
    private UserMapper userMapper;

    @Resource
    private OrderServiceImpl orderService;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private CouponCodeMapper couponCodeMapper;
    @Resource
    private CouponService couponService;
    @Resource
    private MemberServiceImpl memberService;

    /**
     * 抖音回调设置接口
     * @param httpRequest
     * @return
     */
    public JSONObject notifySettings(HttpRequest httpRequest) {
        //回调地址设置
        JSONObject param = new JSONObject();
        //预下单回调
        param.put("create_order_callback", "https://cj.ciaojian.com/bytedance/pay/create_order/notify");
        //退款回调
        param.put("refund_callback", "https://cj.ciaojian.com/bytedance/pay/refundnotify");
        //核销组件二维码跳转地址
        param.put("delivery_qrcode_redirect", "https://cj.ciaojian.com/bytedance/pay/verific");
        //预约回调地址
        param.put("book_callback", "https://cj.ciaojian.com/bytedance/pay/book");
        //定义接收数据
        JSONObject result = new JSONObject();
        try {

            HttpPost httpPost = new HttpPost(ByteDancePayConfig.NOTIFY_SETTINGS);
            CloseableHttpClient client = HttpClients.createDefault();
            StringEntity entity = new StringEntity(param.toString(), "UTF-8");

            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);

            long timestamp = System.currentTimeMillis() / 1000;

            String signature = ByteDanceSignUtil.getSignature("POST", "/api/apps/trade/v2/settings", timestamp, param.toJSONString());

            String sign = " " +
                    "" + ByteDanceMiniConfig.BYTE_AUTHORIZATION + " " +
                    "appid=\"" + ByteDanceMiniConfig.APP_ID + "\"," +
                    "nonce_str=\"" + ByteDanceMiniConfig.NONCE_STR + "\"," +
                    "timestamp=\"" + timestamp + "\"," +
                    "key_version=\"1\"," +
                    "signature=\"" + signature + "\"";

            httpPost.setHeader("Byte-Authorization", sign);
            httpPost.setHeader("Content-Type", "application/json");


            HttpResponse response = client.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                result = JSON.parseObject(EntityUtils.toString(response.getEntity(), "UTF-8"));
            }
            return result;

        } catch (Exception e) {
            return result;
        }
    }

    /**
     * 抖音回调接口查询
     * @param httpRequest
     * @return
     */
    public JSONObject querySettings(HttpRequest httpRequest) {
        //定义接收数据
        JSONObject result = new JSONObject();
        try {

            HttpPost httpPost = new HttpPost(ByteDancePayConfig.QUERY_SETTINGS);
            CloseableHttpClient client = HttpClients.createDefault();


            long timestamp = System.currentTimeMillis() / 1000;

            String signature = ByteDanceSignUtil.getSignature("POST", "/api/apps/trade/v2/query_settings", timestamp, "");

            String sign = " " +
                    "" + ByteDanceMiniConfig.BYTE_AUTHORIZATION + " " +
                    "appid=\"" + ByteDanceMiniConfig.APP_ID + "\"," +
                    "nonce_str=\"" + ByteDanceMiniConfig.NONCE_STR + "\"," +
                    "timestamp=\"" + timestamp + "\"," +
                    "key_version=\"1\"," +
                    "signature=\"" + signature + "\"";

            httpPost.setHeader("Byte-Authorization", sign);
            httpPost.setHeader("Content-Type", "application/json");


            HttpResponse response = client.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                result = JSON.parseObject(EntityUtils.toString(response.getEntity(), "UTF-8"));
            }
            return result;

        } catch (Exception e) {
            return result;
        }
    }
    /**
     * 查看是否已经购买
     *
     * @return
     * @throws Exception
     */
    public Result check_order(Integer userId) {
        User user = userMapper.selectById(userId);
        //已经登陆过潮剪小程序的用户
        QueryWrapper<CouponCode> couponCodeQueryWrapper = new QueryWrapper<>();
        couponCodeQueryWrapper.eq("user_id",user.getId());
        couponCodeQueryWrapper.eq("coupon_id",469);
        List<CouponCode> couponCodes = couponCodeMapper.selectList(couponCodeQueryWrapper);
        if (couponCodes.size()>0) {
            return Result.ok(false);
        }else {
            QueryWrapper<DyOrder> dyOrderQueryWrapper = new QueryWrapper<>();
            dyOrderQueryWrapper.eq("user_id", user.getId());
            dyOrderQueryWrapper.in("status", 3,4,5);
            DyOrder user_id = new DyOrder().selectOne(dyOrderQueryWrapper);
            if (ObjectUtil.isNotNull(user_id)){
                return Result.ok(false);
            }
        }

        return Result.ok(true);
    }


    public JSONObject query_order_v1(String orderNo) throws JsonProcessingException {



        log.info("###预下单接口##");
        JSONObject param = new JSONObject();
        param.put("app_id", ByteDanceMiniConfig.APP_ID);
        param.put("out_order_no", orderNo);
        String sign = Sign.requestSign(param);
        param.put("sign", sign);
        JSONObject result = new JSONObject();
        try {
            String bytedance_clienttoken = byteDanceTokenProvider.getBytedanceClienttoken("BYTEDANCE_CLIENTTOKEN");


            HttpPost httpPost = new HttpPost(ByteDancePayConfig.CREATE_ORDER_V1);
            CloseableHttpClient client = HttpClients.createDefault();
            StringEntity entity = new StringEntity(param.toString(), "UTF-8");

            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);

            httpPost.setHeader("access-token", bytedance_clienttoken);
            HttpResponse response = client.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                result = JSON.parseObject(EntityUtils.toString(response.getEntity(), "UTF-8"));
            }
            return result;

        } catch (Exception e) {
            System.out.println(e.getMessage());
            return result;
        }
    }

    /**
     * 担保支付发起
     */
    @Transactional
    public Result create_order_v1(HttpServletRequest request,
                                  OrderCreateRequestVo orderCreateRequestVo) throws JsonProcessingException {
        JSONObject param = new JSONObject();
        Double paytotal = 0D;
        QueryWrapper<Order> wrapper = new QueryWrapper<>();
        wrapper.eq("order_no", orderCreateRequestVo.getOrderNo());
        Order order = orderMapper.selectOne(wrapper);

        // 订单号
//        if (order == null) {
//            return Result.error("订单不存在");
//        }
//        if (!order.getStatus().equals(OrderStatusEnum.wait_pay) && !order.getStatus().equals(OrderStatusEnum.servicing)
//                && !order.getStatus().equals(OrderStatusEnum.sling)) {
//            LogUtil.writePayLog(">>>wxPay>>>订单[id={},orderNo={}]的状态={}不是待付款", order.getId(), order.getOrderNo(), order.getStatus());
//            return Result.error("订单当前不可付款");
//        }

        // 订单总价
        final BigDecimal money = order.getGoodsTotal();

        String prefix = new SimpleDateFormat("yyyyMMddHHmmsss").format(new Date());
        String newOrderNo = prefix.concat("I").concat(String.valueOf(order.getId()));

        LogUtil.writePayLog(">>>wxPay>>>新订单号={},旧订单号={}", newOrderNo, order.getOrderNo());


        // 拿到用户获取会员的时间
        // 如果用户优惠 id 不为 null 进这个判断
        if (ObjectUtil.isNotNull(orderCreateRequestVo.getMemberDiscountId())) {
            // 会员优惠
            MemberDiscount memberDiscount = new MemberDiscount().selectById(orderCreateRequestVo.getMemberDiscountId());
            // 校验优惠是否有效
            if (memberDiscount == null || memberDiscount.getOrderId() != null) {
                LogUtil.writePayLog(">>>优惠不存在或已被使用,memberDiscount={}>>>", memberDiscount);
                return Result.error("优惠不存在或已被使用");
            }
            // 校验 memberDiscount 的 userId 和 order 的 userId 是否一致
            if (!memberDiscount.getUserId().equals(order.getUserId())) {
                LogUtil.writePayLog(">>>优惠所属用户和订单用户不一致,memberDiscount.getUserId():{},order2.getUserId():{}>>>", memberDiscount, order.getUserId());
                return Result.error("优惠所属用户和订单用户不一致");
            }

            LogUtil.writePayLog(">>>wxPay,memberDiscount:{},userId:{}>>>", memberDiscount, order.getUserId());
            // 支付时先把订单号放进去,在支付成功回调的方法处再把订单 id 放进去,订单 id 不为 null 时才表示已被使用
            memberDiscount.setOrderNo(newOrderNo);
            memberDiscount.updateById();
        } else {
            // 用户使用了优惠劵
            List<String> codeList = Arrays.asList(orderCreateRequestVo.getCodes());
            BigDecimal reductionTotal = BigDecimal.ZERO;
            if (CollUtil.isNotEmpty(codeList)) {
                for (String code : codeList) {
                    CouponVo couponVo = myCouponMapper.getCouponByCode(code);
                    Assert.notNull(couponVo, "优惠券不存在");
                    switch (couponVo.getCouponType()) {
                        // 满减券
                        case 0:
                            reductionTotal = reductionTotal.add(couponVo.getReduction());
                            break;
                        // 折扣券
                        case 1:
                            reductionTotal = reductionTotal.add(money.multiply(couponVo.getDiscount()));
                            break;
                        default:
                    }
                }
                order.setCouponTotal(reductionTotal);
            }
            // 用户没有使用优惠劵
            else {
                UpdateWrapper<Order> updateWrapper = new UpdateWrapper<>();
                updateWrapper.set("coupon_code", null);
                updateWrapper.set("coupon_total", 0);
                updateWrapper.eq("order_no", newOrderNo);
                orderMapper.update(order,updateWrapper);
            }
            // 计算优惠后的价格
            BigDecimal discountPrice = orderService.calDiscountV2(order, Arrays.asList(orderCreateRequestVo.getCodes()), orderCreateRequestVo.getType(),orderCreateRequestVo.getMemberDiscountId(), money, order.getUserId());
            paytotal = discountPrice.doubleValue();
        }
        paytotal = paytotal * 100;

        //请求抖音
        log.info("###预下单接口##");
        param.put("app_id", ByteDanceMiniConfig.APP_ID);
        param.put("out_order_no", order.getOrderNo());
        param.put("total_amount", paytotal.intValue()); //1
        param.put("subject", "剪发服务");
        param.put("body", "剪发服务");
        param.put("valid_time", 172800);
        param.put("cp_extra", "");
        param.put("notify_url", "https://cj.ciaojian.com/bytedance/notify/jianfa/dyNotify");
        String sign = Sign.requestSign(param);
        param.put("sign", sign);

        JSONObject result = new JSONObject();
        try {
            String bytedance_clienttoken = byteDanceTokenProvider.getBytedanceClienttoken("BYTEDANCE_CLIENTTOKEN");


            HttpPost httpPost = new HttpPost(ByteDancePayConfig.CREATE_ORDER_V1);
            CloseableHttpClient client = HttpClients.createDefault();
            StringEntity entity = new StringEntity(param.toString(), "UTF-8");

            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);

            httpPost.setHeader("access-token", bytedance_clienttoken);
            HttpResponse response = client.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                result = JSON.parseObject(EntityUtils.toString(response.getEntity(), "UTF-8"));
                PayV1Vo payV1Vo = result.toJavaObject(PayV1Vo.class);
                return Result.ok(200,payV1Vo.getErr_tips(),payV1Vo.getData());
            }
            return  Result.error("请求抖音失败");
        } catch (Exception e) {
            return Result.error("系统错误");
        }
    }

    /**
     * 预下单回调
     * @param createOrderNotifyVo
     * @return
     */
    public ByteDanceOrderNotifyResponseVo createOrderNotify(NotifyVo createOrderNotifyVo) throws Exception {
        log.info("###预下单回调##");
        String s = JsonUtil.toJson(createOrderNotifyVo);
        log.info("#预下单参数#" + s);
        System.out.println("#预下单参数sout" + s);
        ByteDanceOrderNotifyResponseVo byteDanceHttpResponseVo = new ByteDanceOrderNotifyResponseVo();
        byteDanceHttpResponseVo.setErr_no(0);
        byteDanceHttpResponseVo.setErr_tips("success");

        OrderMsgVo orderMsgVo = JsonUtil.fromJson(createOrderNotifyVo.getMsg(), OrderMsgVo.class);
        System.out.println(JsonUtil.toJson(orderMsgVo));
        /**订单号*/
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("dy_openid", orderMsgVo.getOpen_id());
        User user = UserMapper.selectOne(userQueryWrapper);
        String orderNo = bytePayService.getNewOrderNo(user);

        ByteDanceOrderNotifyResponseVo.DataBean dataBean = new ByteDanceOrderNotifyResponseVo.DataBean();
        dataBean.setOut_order_no(orderNo); //开发者的单号
        dataBean.setPay_expire_seconds(300); //单位秒

        /*订单详情页信息*/
        ByteDanceOrderNotifyResponseVo.DataBean.OrderEntrySchemaBean orderEntrySchemaBean = new ByteDanceOrderNotifyResponseVo.DataBean.OrderEntrySchemaBean();
        orderEntrySchemaBean.setParams("{\"dyOrderId\": \""+orderMsgVo.getOrder_id()+"\",\"orderNo\": \""+orderNo+"\"}");
        orderEntrySchemaBean.setPath("pages/order/detail/orderDetail");
        dataBean.setOrder_entry_schema(orderEntrySchemaBean);

        /*卷的有效期设置*/
//        ByteDanceOrderNotifyResponseVo.DataBean.OrderValidTimeBean orderValidTimeBean = new ByteDanceOrderNotifyResponseVo.DataBean.OrderValidTimeBean();
//        orderValidTimeBean.setValid_start_time();
//        orderValidTimeBean.setValid_end_time();
//        orderValidTimeBean.setGoods_id();

        /*二维码*/
        dataBean.setCp_delivery_type(0);
        dataBean.setDelivery_type(1);
        dataBean.setDelivery_qrcode_redirect("https://cj.ciaojian.com/bytedance/pay/verific");

        byteDanceHttpResponseVo.setData(dataBean);


        List<OrderMsgVo.GoodsBean> goodsBean = orderMsgVo.getGoods();

        QueryWrapper<DyOrder> dyOrderQueryWrapper = new QueryWrapper<DyOrder>();
        dyOrderQueryWrapper.eq("dy_order_id", orderMsgVo.getOrder_id());
        DyOrder dyOrderExist = dyOrderMapper.selectOne(dyOrderQueryWrapper);

        if (ObjectUtil.isNotNull(dyOrderExist)) {
            dyOrderExist.setUserId(user.getId());
            dyOrderExist.setPhoneNum(orderMsgVo.getPhone_num());

            //商品信息
            for (OrderMsgVo.GoodsBean goods : goodsBean) {
                dyOrderExist.setType(goods.getTitle());
                dyOrderExist.setGoodsDyId(goods.getGoods_id());
                BigDecimal price = new BigDecimal(goods.getPrice());
                price = price.divide(new BigDecimal(100), 2, BigDecimal.ROUND_UNNECESSARY);
                dyOrderExist.setGoodsTotal(price);
            }
            //总金额
            BigDecimal price = new BigDecimal(orderMsgVo.getTotal_amount());
            price = price.divide(new BigDecimal(100), 2, BigDecimal.ROUND_UNNECESSARY);
            dyOrderExist.setTotal(price);

            //抖音内部订单号
            dyOrderExist.setDyOrderId(orderMsgVo.getOrder_id());

            dyOrderExist.setOrderNo(orderNo);

            //待支付
            dyOrderExist.setStatus(0);

            dyOrderExist.setAddTime(new Date());
            dyOrderExist.setUpdateTime(new Date());

            dyOrderExist.setChannel("抖音小程序");
            dyOrderMapper.updateById(dyOrderExist);
        } else {
            /*订单入库*/
            DyOrder dyOrder = new DyOrder();
            dyOrder.setUserId(user.getId());
            dyOrder.setPhoneNum(orderMsgVo.getPhone_num());

            //商品信息
            for (OrderMsgVo.GoodsBean goods : goodsBean) {
                dyOrder.setType(goods.getTitle());
                dyOrder.setGoodsDyId(goods.getGoods_id());
                BigDecimal price = new BigDecimal(goods.getPrice());
                price = price.divide(new BigDecimal(100), 2, BigDecimal.ROUND_UNNECESSARY);
                dyOrder.setGoodsTotal(price);
            }


            //总金额
            BigDecimal price = new BigDecimal(orderMsgVo.getTotal_amount());
            price = price.divide(new BigDecimal(100), 2, BigDecimal.ROUND_UNNECESSARY);
            dyOrder.setTotal(price);

            //抖音内部订单号
            dyOrder.setDyOrderId(orderMsgVo.getOrder_id());

            dyOrder.setOrderNo(orderNo);

            //待支付
            dyOrder.setStatus(0);

            dyOrder.setAddTime(new Date());
            dyOrder.setUpdateTime(new Date());

            dyOrder.setChannel("抖音小程序");

            dyOrderMapper.insert(dyOrder);
        }


        return byteDanceHttpResponseVo;
    }

    /**
     * 订单详情
     * @param orderId
     * @return
     */
    public Result queryOrder(String orderId) {
        JSONObject param = new JSONObject();
        param.put("order_id", orderId);
        param.put("out_order_no", orderId);
        //定义接收数据
        JSONObject result = new JSONObject();
        try {

            HttpPost httpPost = new HttpPost(ByteDancePayConfig.QUERY_ORDER);
            CloseableHttpClient client = HttpClients.createDefault();
            StringEntity entity = new StringEntity(param.toString(), "UTF-8");

            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);


            long timestamp = System.currentTimeMillis() / 1000;
            String signature = ByteDanceSignUtil.getSignature("POST", "/api/apps/trade/v2/query_order", timestamp, param.toJSONString());

            String sign = " " +
                    "" + ByteDanceMiniConfig.BYTE_AUTHORIZATION + " " +
                    "appid=\"" + ByteDanceMiniConfig.APP_ID + "\"," +
                    "nonce_str=\"" + ByteDanceMiniConfig.NONCE_STR + "\"," +
                    "timestamp=\"" + timestamp + "\"," +
                    "key_version=\"1\"," +
                    "signature=\"" + signature + "\"";

            httpPost.setHeader("Byte-Authorization", sign);
            httpPost.setHeader("Content-Type", "application/json");


            HttpResponse response = client.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                result = JSON.parseObject(EntityUtils.toString(response.getEntity(), "UTF-8"));
            }

            ByteOrderInfoVo byteOrderInfoVo = result.toJavaObject(ByteOrderInfoVo.class);

            QueryWrapper<DyOrder> dyOrderQueryWrapper = new QueryWrapper<DyOrder>();
            dyOrderQueryWrapper.eq("dy_order_id", byteOrderInfoVo.getData().getOrder_id());

            DyOrder dyOrder = dyOrderMapper.selectOne(dyOrderQueryWrapper);

            return Result.ok(dyOrder);

        } catch (Exception e) {
            return Result.ok(result);
        }
    }

    //核销组件二维码跳转地址
    public Result verificNotify(String encrypted_data, String app_id, String out_order_no, String code) {
        log.info("##核销组件二维码跳转地址");
        String bytedance_clienttoken = byteDanceTokenProvider.getBytedanceClienttoken("BYTEDANCE_CLIENTTOKEN");
        //回调地址设置
        JSONObject param = new JSONObject();
        param.put("encrypted_data", encrypted_data);
        param.put("code", code);
//        param.put("out_order_no ", out_order_no);
//        param.put("app_id ", app_id);
        //定义接收数据
        JSONObject result = new JSONObject();
        try {

            HttpPost httpPost = new HttpPost(ByteDancePayConfig.DELIVERY_PREPARE);
            CloseableHttpClient client = HttpClients.createDefault();
            StringEntity entity = new StringEntity(param.toString(), "UTF-8");

            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);
            Date date = new Date();
            long timestamp = date.getTime() / 1000;

            String signature = ByteDanceSignUtil.getSignature("POST", "/api/apps/trade/v2/delivery_prepare", timestamp, param.toJSONString());

            String sign = " " +
                    "" + ByteDanceMiniConfig.BYTE_AUTHORIZATION + " " +
                    "appid=\"" + ByteDanceMiniConfig.APP_ID + "\"," +
                    "nonce_str=\"" + ByteDanceMiniConfig.NONCE_STR + "\"," +
                    "timestamp=\"" + timestamp + "\"," +
                    "key_version=\"1\"," +
                    "signature=\"" + signature + "\"";

            httpPost.setHeader("Byte-Authorization", sign);
            httpPost.setHeader("Content-Type", "application/json");
            httpPost.setHeader("access-token", bytedance_clienttoken);


            HttpResponse response = client.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                result = JSON.parseObject(EntityUtils.toString(response.getEntity(), "UTF-8"));
                DeliveryPrepareVo deliveryPrepareVo = result.toJavaObject(DeliveryPrepareVo.class);
                log.info("##核销准备={}", deliveryPrepareVo);
                if (ObjectUtil.isNotNull(deliveryPrepareVo.getData())) {
                    String deliveryStr = JsonUtil.toJson(deliveryPrepareVo);
                    try {
                        RedisUtil.delKey("BYTEDANCEVERIFIC::" + deliveryPrepareVo.getData().getOut_order_no());
                    } catch (Exception e) {

                    }
                    RedisUtil.setKeyTime("BYTEDANCEVERIFIC::" + deliveryPrepareVo.getData().getOut_order_no(), 7200, deliveryStr, DateUnit.SECOND);
                    return Result.ok(deliveryPrepareVo.getData().getOut_order_no());
                }
            }

            return Result.fail(StatusCode.FAIL, "已核销");

        } catch (Exception e) {
            return Result.error(e.getMessage());
        }
    }
    /**
     * 抖音核销接口
     *
     * @param orderNo
     * @param workerId
     * @param storeId
     * @return
     * @throws Exception
     */
    @Transactional
    public Result postverifyNotify(String orderNo, String workerId, String storeId) {
        try {

            if(ObjectUtil.isNull(workerId)||ObjectUtil.isNull(storeId)){
                return Result.ok("请在潮剪端核销!!!");
            }

            QueryWrapper<DyOrder> dyOrderMapperQueryWrapper = new QueryWrapper<>();
            dyOrderMapperQueryWrapper.eq("order_no", orderNo);
            DyOrder dyOrder = dyOrderMapper.selectOne(dyOrderMapperQueryWrapper);
            Worker worker = workerMapper.selectById(workerId);
            Store store = storeMapper.selectById(storeId);

            String key = RedisUtil.getKey("BYTEDANCEVERIFIC::" + orderNo);
            if (ObjectUtil.isNotNull(key)) {
                DeliveryPrepareVo deliveryPrepareVo = JsonUtil.fromJson(key, DeliveryPrepareVo.class);
                log.info("##核销redis={}", deliveryPrepareVo);
                boolean delKey = RedisUtil.delKey("BYTEDANCEVERIFIC::" + orderNo);
                log.info("##核销redis删除={}", delKey);

                log.info("##核销组件二维码跳转地址");
                String bytedance_clienttoken = byteDanceTokenProvider.getBytedanceClienttoken("BYTEDANCE_CLIENTTOKEN");
                //回调地址设置
                JSONObject param = new JSONObject();
                param.put("verify_token", deliveryPrepareVo.getData().getVerify_token());
                param.put("certificates", deliveryPrepareVo.getData().getCertificates());
                param.put("order_id", deliveryPrepareVo.getData().getOrder_id());
                param.put("poi_info", "{\"shop_name\":\"潮剪(东方宝泰店)\",\"ext_valid_shop_id\":\"6729124296515487756\",\"valid_poi_id_str\":\"7\"}");

                //定义接收数据
                JSONObject result = new JSONObject();

                HttpPost httpPost = new HttpPost(ByteDancePayConfig.DELIVERY_VERIFY);
                CloseableHttpClient client = HttpClients.createDefault();
                StringEntity entity = new StringEntity(param.toString(), "UTF-8");

                entity.setContentEncoding("UTF-8");
                entity.setContentType("application/json");
                httpPost.setEntity(entity);

                Date date = new Date();
                long timestamp = date.getTime() / 1000;


                String signature = ByteDanceSignUtil.getSignature("POST", "/api/apps/trade/v2/delivery_verify", timestamp, param.toJSONString());

                String sign = " " +
                        "" + ByteDanceMiniConfig.BYTE_AUTHORIZATION + " " +
                        "appid=\"" + ByteDanceMiniConfig.APP_ID + "\"," +
                        "nonce_str=\"" + ByteDanceMiniConfig.NONCE_STR + "\"," +
                        "timestamp=\"" + timestamp + "\"," +
                        "key_version=\"1\"," +
                        "signature=\"" + signature + "\"";

                httpPost.setHeader("Byte-Authorization", sign);
                httpPost.setHeader("Content-Type", "application/json");
                httpPost.setHeader("access-token", bytedance_clienttoken);

                HttpResponse response = client.execute(httpPost);
                if (response.getStatusLine().getStatusCode() == 200) {
                    result = JSON.parseObject(EntityUtils.toString(response.getEntity(), "UTF-8"));

                    if (result.get("err_tips").equals("success")) {
                        VerifyEndVo verifyEndVo = result.toJavaObject(VerifyEndVo.class);
                        log.info("###核销完成={}", verifyEndVo);
                        if (ObjectUtil.isNotNull(verifyEndVo.getData())) {
                            List<VerifyEndVo.DataBean.VerifyResultsBean> verify_results = verifyEndVo.getData().getVerify_results();
                            for (VerifyEndVo.DataBean.VerifyResultsBean verify_result : verify_results) {
                                if (verify_result.getResult_code() == 0) {

                                    /**
                                     * 发券
                                     */
                                    User user = userMapper.selectById(dyOrder.getUserId());
                                    if (ObjectUtil.isNotNull(dyOrder.getCouponId())&&dyOrder.getCouponId()==469) {
                                        if (ObjectUtil.isNotNull(user)) {
                                            //已经登陆过潮剪小程序的用户
                                            QueryWrapper<CouponCode> couponCodeQueryWrapper = new QueryWrapper<>();
                                            couponCodeQueryWrapper.eq("user_id", user.getId());
                                            couponCodeQueryWrapper.eq("coupon_id", 469);
                                            List<CouponCode> couponCodes = couponCodeMapper.selectList(couponCodeQueryWrapper);
                                            if (couponCodes.size() > 0) {
                                                //暂不做操作
                                            } else {
                                                //券码号
                                                dyOrder.setCouponId(469);

                                                QueryWrapper<CouponCode> queryWrapper = new QueryWrapper<>();
                                                queryWrapper.eq("coupon_id", 469)
                                                        .eq("status", 0)
                                                        .isNull("user_id")
                                                        .last("limit 1");
                                                CouponCode couponCode = new CouponCode().selectOne(queryWrapper);
                                                Assert.notNull(couponCode, "券码已被抢完");

                                                couponCode.setStatus(1);
                                                couponCode.setUserId(user.getId());
                                                couponCode.setOrigin(CouponCodeOriginEnum.DOUYIN_WRITE_OFF);
                                                couponCode.setExpiredTime(couponService.getCouponExpiredTime(469));
                                                couponCode.setUpdateTime(new Date());
                                                couponCode.setRemark(dyOrder.getDyOrderId());
                                                couponCode.updateById();

                                                dyOrder.setStatus(4);
                                                dyOrder.setCouponCode(couponCode.getCode());
                                                dyOrder.setWorkerName(worker.getName());
                                                dyOrder.setWorkerId(worker.getId());
                                                dyOrder.setStoreId(store.getId());
                                                dyOrder.setStoreName(store.getTitle());
                                                dyOrder.setDyCode(verify_result.getCertificate_code());
                                                dyOrder.setVefiTime(new Date());
                                                dyOrder.updateById();

                                                couponService.addGetNum(469);

                                                CouponCodeTakeRecord couponCodeTakeRecord = new CouponCodeTakeRecord();
                                                couponCodeTakeRecord.setUserId(user.getId());
                                                couponCodeTakeRecord.setCouponId(469);
                                                couponCodeTakeRecord.setCouponCode(couponCode.getCode());
                                                couponCodeTakeRecord.setActivityId(4);
                                                couponCodeTakeRecord.setType(CouponCodeTakeRecordTypeEnum.DOUYIN_WRITE_OFF);
                                                couponCodeTakeRecord.insert();

                                            }
                                        }
                                    }


                                    try {
                                        if (ObjectUtil.isNotNull(dyOrder.getMemberId())&&dyOrder.getMemberId()!=0) {
                                            memberService.send(dyOrder, worker);
                                            dyOrder.setStoreId(store.getId());
                                            dyOrder.setStoreName(store.getTitle());
                                            dyOrder.setStatus(5);
                                            dyOrder.setVefiTime(new Date());
                                            dyOrder.updateById();


                                            Order order = new Order();
                                            order.setUserId(dyOrder.getUserId());
                                            order.setStoreName(store.getTitle());
                                            order.setWorkerName(dyOrder.getWorkerName());
                                            order.setWorkerId(dyOrder.getWorkerId());
                                            order.setStoreId(dyOrder.getStoreId());
                                            order.setType(dyOrder.getType());
                                            order.setGoodsTotal(new BigDecimal(0));
                                            order.setTotal(new BigDecimal(0));
                                            order.setOrderNo(dyOrder.getOrderNo());
                                            order.setAddTime(new Date());
                                            order.setPayTime(dyOrder.getPayTime());
                                            order.setPayTotal(new BigDecimal(0));
                                            order.setStatus(OrderStatusEnum.complete);
                                            order.setPayType(dyOrder.getPayType());
                                            if (ObjectUtil.isNotNull(dyOrder.getDyCode())) {
                                                order.setYouzanCode(dyOrder.getDyCode());
                                            }
                                            order.setChannel(2);
                                            order.setOrderType(OrderOrderTypeEnum.MEMBER_DETAIL);
                                            order.setUpdateTime(dyOrder.getVefiTime());
                                            if (dyOrder.getIsUserMember()==1){
                                                order.setIsUserMember(OrderIsUserMemberEnum.VALID_MEMBER);
                                            }else if(dyOrder.getIsUserMember()==0){
                                                order.setIsUserMember(OrderIsUserMemberEnum.EXPIRED_MEMBER);
                                            }else if(dyOrder.getIsUserMember()==-1){
                                                order.setIsUserMember(OrderIsUserMemberEnum.NON_MEMBER);
                                            }
                                            order.insert();

                                        }
                                    }catch (Exception e){}

                                }
                            }
                            return Result.ok(result);
                        }
                    }
                }

            }
            return Result.fail(StatusCode.FAIL, "已核销");

        } catch (Exception e) {
            return Result.fail(StatusCode.FAIL, "已核销");
        }

    }
    /**
     * 退款回调接口
     *
     * @param refundCallbackVo
     * @return
     */
    public ByteDanceRefundNotifyResponseVo refundNotify(NotifyVo refundCallbackVo) {
        log.info("###退款1={}", refundCallbackVo);

        ByteDanceRefundNotifyResponseVo byteDanceRefundvo = new ByteDanceRefundNotifyResponseVo();
        byteDanceRefundvo.setErr_no(0);
        byteDanceRefundvo.setErr_tips("success");

        ByteDanceRefund byteDanceRefund = JsonUtil.fromJson(refundCallbackVo.getMsg(), ByteDanceRefund.class);
        log.info("###退款2={}", byteDanceRefund);

        ByteDanceRefundNotifyResponseVo.DataBean dataBean = new ByteDanceRefundNotifyResponseVo.DataBean();

        ByteDanceRefundNotifyResponseVo.DataBean.OrderEntrySchemaBean orderEntrySchemaBean = new ByteDanceRefundNotifyResponseVo.DataBean.OrderEntrySchemaBean();

        orderEntrySchemaBean.setPath("bdp_dynamic_plugins/microapp-trade-plugin/pages/refund-detail/index");
        orderEntrySchemaBean.setParams("bdp_dynamic_plugins/microapp-trade-plugin/pages/refund-detail/index");


        orderEntrySchemaBean.setPath("pages/order/detail/orderDetail");
        orderEntrySchemaBean.setParams("{\"dyOrderId\": \""+byteDanceRefund.getOrder_id()+"\",\"orderNo\": \""+byteDanceRefund.getOut_order_no()+"\"}");


        dataBean.setOrder_entry_schema(orderEntrySchemaBean);
        dataBean.setOut_refund_no(byteDanceRefund.getOut_order_no());

        byteDanceRefundvo.setData(dataBean);

        QueryWrapper<DyOrder> dyOrderQueryWrapper = new QueryWrapper<>();
        dyOrderQueryWrapper.eq("order_no", byteDanceRefund.getOut_order_no());
        DyOrder dyOrder = dyOrderMapper.selectOne(dyOrderQueryWrapper);
        dyOrder.setRefundId(byteDanceRefund.getRefund_id());

        BigDecimal price = new BigDecimal(byteDanceRefund.getRefund_total_amount());
        price = price.divide(new BigDecimal(100), 2, BigDecimal.ROUND_UNNECESSARY);
        dyOrder.setRefundTotal(price);
        if (byteDanceRefund.getRefund_reason().size() > 0) {
            dyOrder.setRefundReason(byteDanceRefund.getRefund_reason().get(0));
        }
        dyOrder.setRefundSource(byteDanceRefund.getRefund_source());
        dyOrder.setStatus(-2);



        JSONObject param = new JSONObject();
        param.put("out_refund_no", byteDanceRefund.getOrder_id());
        //定义接收数据
        JSONObject result = new JSONObject();

        dyOrder.updateById();
        return byteDanceRefundvo;
    }

    /**
     * 退款审核结果同步
     * @param outRefundNo
     * @param status
     * @param message
     * @return
     * @throws Exception
     */
    public JSONObject merchantAudit(String outRefundNo, Integer status, String message) throws Exception {

        JSONObject param = new JSONObject();
        param.put("out_refund_no", outRefundNo);
        //退款状态 1同意 2拒绝
        param.put("refund_audit_status", status);
        param.put("deny_message", message);

        QueryWrapper<DyOrder> dyOrderQueryWrapper = new QueryWrapper<>();
        dyOrderQueryWrapper.eq("order_no", outRefundNo);
        DyOrder dyOrder = dyOrderMapper.selectOne(dyOrderQueryWrapper);
        if(dyOrder.getStatus()!=-2){
            throw new Exception("未申请退款");
        }

        //定义接收数据
        JSONObject result = new JSONObject();
        try {

            HttpPost httpPost = new HttpPost(ByteDancePayConfig.MERCHANT_AUDIT_CALLBACK);
            CloseableHttpClient client = HttpClients.createDefault();
            StringEntity entity = new StringEntity(param.toString(), "UTF-8");

            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);

            long timestamp = System.currentTimeMillis() / 1000;

            String signature = ByteDanceSignUtil.getSignature("POST", "/api/apps/trade/v2/merchant_audit_callback", timestamp, param.toJSONString());

            String sign = " " +
                    "" + ByteDanceMiniConfig.BYTE_AUTHORIZATION + " " +
                    "appid=\"" + ByteDanceMiniConfig.APP_ID + "\"," +
                    "nonce_str=\"" + ByteDanceMiniConfig.NONCE_STR + "\"," +
                    "timestamp=\"" + timestamp + "\"," +
                    "key_version=\"1\"," +
                    "signature=\"" + signature + "\"";

            httpPost.setHeader("Byte-Authorization", sign);
            httpPost.setHeader("Content-Type", "application/json");


            HttpResponse response = client.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                result = JSON.parseObject(EntityUtils.toString(response.getEntity(), "UTF-8"));
                if (status == 1 && result.get("err_tips").equals("success")) {
                    //同意退款
                    dyOrder.setStatus(-3);
                    dyOrder.setRefundResult(1);
                    if (ObjectUtil.isNotNull(dyOrder.getCouponCode())) {
                        couponCodeMapper.removeUserCoupon(dyOrder.getCouponCode());
                    }
                    Oplog dOplog = new Oplog();
                    dOplog.setAccount("admin");
                    dOplog.setModular("抖音用户退款");
                    dOplog.setContent("dy用户id：" + dyOrder.getUserId() + "，券码:" + dyOrder.getCouponCode());
                    dOplog.insert();

                    dyOrder.setCouponCode("");
                    dyOrder.updateById();
                }
                if (status == 2 && result.get("err_tips").equals("success")){
                    //拒绝退款
//                    QueryWrapper<DyOrder> dyOrderQueryWrapper = new QueryWrapper<>();
//                    dyOrderQueryWrapper.eq("order_no", outRefundNo);
//                    DyOrder dyOrder = dyOrderMapper.selectOne(dyOrderQueryWrapper);
                    dyOrder.setStatus(3);

                    if (ObjectUtil.isNotNull(dyOrder.getCouponCode())) {
                        QueryWrapper<CouponCode> couponCodeQueryWrapper = new QueryWrapper<>();
                        couponCodeQueryWrapper.eq("code", dyOrder.getCouponCode());
                        CouponCode couponCode = couponCodeMapper.selectOne(couponCodeQueryWrapper);
                        if (couponCode.getStatus() == 1) {
                            dyOrder.setStatus(4);
                        }
                        if (couponCode.getStatus() == 2) {
                            dyOrder.setStatus(5);
                        }
                    }

                    dyOrder.setRefundResult(2);
                    dyOrder.setCancelReason(message);
                    dyOrder.updateById();
                }
            }
            return result;

        } catch (Exception e) {
            return result;
        }
    }

    /**
     * 退款单查询
     * @param orderNo
     * @return
     */
    public JSONObject queryRefund( String orderNo) {
        JSONObject param = new JSONObject();
        param.put("refund_id", orderNo);

        //定义接收数据
        JSONObject result = new JSONObject();
        try {

            HttpPost httpPost = new HttpPost(ByteDancePayConfig.QUERY_REFUND);
            CloseableHttpClient client = HttpClients.createDefault();
            StringEntity entity = new StringEntity(param.toString(), "UTF-8");

            entity.setContentEncoding("UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);

            long timestamp = System.currentTimeMillis() / 1000;

            String signature = ByteDanceSignUtil.getSignature("POST", "/api/apps/trade/v2/query_refund", timestamp, param.toJSONString());

            String sign = " " +
                    "" + ByteDanceMiniConfig.BYTE_AUTHORIZATION + " " +
                    "appid=\"" + ByteDanceMiniConfig.APP_ID + "\"," +
                    "nonce_str=\"" + ByteDanceMiniConfig.NONCE_STR + "\"," +
                    "timestamp=\"" + timestamp + "\"," +
                    "key_version=\"1\"," +
                    "signature=\"" + signature + "\"";

            httpPost.setHeader("Byte-Authorization", sign);
            httpPost.setHeader("Content-Type", "application/json");


            HttpResponse response = client.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == 200) {
                result = JSON.parseObject(EntityUtils.toString(response.getEntity(), "UTF-8"));

                QueryWrapper<DyOrder> dyOrderQueryWrapper = new QueryWrapper<>();
                dyOrderQueryWrapper.eq("refund_id",orderNo);
                DyOrder dyOrder = dyOrderMapper.selectOne(dyOrderQueryWrapper);

                QueryRefundVo queryRefundVo = result.toJavaObject(QueryRefundVo.class);
                if ("SUCCESS".equals(queryRefundVo.getData().getRefund_status())){
                    dyOrder.setStatus(-3);
                    dyOrder.setRefundResult(1);
                    dyOrder.setCancelResult(queryRefundVo.getData().getMerchant_audit_detail().getAudit_status());
                    if (ObjectUtil.isNotNull(dyOrder.getCouponCode())) {
                        couponCodeMapper.removeUserCoupon(dyOrder.getCouponCode());
                    }
                    dyOrderMapper.updateById(dyOrder);
                }

                dyOrder.setStatus(3);

                if (ObjectUtil.isNotNull(dyOrder.getCouponCode())) {
                    QueryWrapper<CouponCode> couponCodeQueryWrapper = new QueryWrapper<>();
                    couponCodeQueryWrapper.eq("code", dyOrder.getCouponCode());
                    CouponCode couponCode = couponCodeMapper.selectOne(couponCodeQueryWrapper);
                    if (couponCode.getStatus() == 1) {
                        dyOrder.setStatus(4);
                    }
                    if (couponCode.getStatus() == 2) {
                        dyOrder.setStatus(5);
                    }
                }

                dyOrder.setRefundResult(2);
                dyOrder.setCancelResult(queryRefundVo.getData().getMerchant_audit_detail().getAudit_status());
                dyOrderMapper.updateById(dyOrder);

            }

            return result;

        } catch (Exception e) {
            return result;
        }
    }

}
